package com.door.erp.dao.base;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

/**
 * Dao层通用方法实现
 * @author yangxuelin
 */
public abstract class GenericDaoImpl<T, PK extends Serializable> implements GenericDao<T, PK> {

	protected final Logger log = Logger.getLogger(getClass());
	
	@Resource(name = "hibernateTemplate", type = HibernateTemplate.class)
	private HibernateTemplate hibernateTemplate;
	
	protected abstract Class<T> getPersistentClass();
	
	public HibernateTemplate getHibernateTemplate() {
		return this.hibernateTemplate;
	}

	@Override
	public void add(T object) {
		getHibernateTemplate().save(object);		
	}

	@Override
	public void delete(PK id) {
		getHibernateTemplate().delete(getHibernateTemplate().get(getPersistentClass(), id));
	}

	@Override
	public void modify(T object) {
		getHibernateTemplate().update(object);
	}

	@Override
	public T get(PK id) {
		return (T)getHibernateTemplate().get(getPersistentClass(), id);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(final String hql) {
		return getHibernateTemplate().find(hql);
	}


	@Override
	public List<T> getAll() {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				return (List<T>) criteria.list();
			}
		});
	}
	
	@Override
	public List<T> getAll(final int startRow, final int pageSize) {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				criteria.setFirstResult(startRow);
				criteria.setMaxResults(pageSize);
				return (List<T>) criteria.list();
			}
		});
	}
	
	@Override
	public void addOrUpdate(T object) {
		getHibernateTemplate().saveOrUpdate(object);		
	}

	@Override
	public void delete(T object) {
		getHibernateTemplate().delete(object);		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(final Map<String, Object> params) {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				criteria.add(Restrictions.allEq(params));
				return (List<T>) criteria.list();
			}
		});
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(final Map<String, Object> params, final int startRow,
			final int pageSize) {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				if(params != null)
					criteria.add(Restrictions.allEq(params));
				criteria.setFirstResult(startRow);
				criteria.setMaxResults(pageSize);
				return (List<T>) criteria.list();
			}
		});
	}
	
	@Override
	public int getCount() {
		return this.hibernateTemplate.execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				long count = (Long)criteria.setProjection(Projections.rowCount()).uniqueResult();
				return (int)count;
			}
		});
	}

	@Override
	public int getCount(final Map<String, Object> params) {
		return this.hibernateTemplate.execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(getPersistentClass());
				criteria.add(Restrictions.allEq(params));
				long count = (Long)criteria.setProjection(Projections.rowCount()).uniqueResult();
				return (int)count;
			}
		});
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(String hql, Object... values) {
		return getHibernateTemplate().find(hql, values);
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll(final String hql, final Object[] params, final int startRow,
			final int pageSize) {
		return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				if(params != null && params.length > 0) {
					for(int i = 0; i < params.length; i++) {
						query.setParameter(i, params[i]);
					}
				}
				List<?> result = query.setFirstResult(startRow).setMaxResults(pageSize).list();
				return result;
			}
		});
	}

	@Override
	public int getCount(String hql, Object... params) {
		List list = getHibernateTemplate().find(hql, params);
		return DataAccessUtils.intResult(list);
	}

	@Override
	public Integer executeUpdateByQuery(String sql, Object[] params) {
		return getHibernateTemplate().bulkUpdate(sql, params);
	}

	@Override
	public void flush() {
		getHibernateTemplate().flush();		
	}
	
}
